package versi.vitro.oaiserviceprovider.service.jena.impl;

import java.io.PrintWriter;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import versi.vitro.oaiserviceprovider.service.jena.api.JenaHelper;
import versi.vitro.oaiserviceprovider.service.jena.api.JenaService;
import versi.vitro.oaiserviceprovider.service.jena.api.ModelBuilder;
import versi.vitro.oaiserviceprovider.service.jena.api.SparqlQueryEngine;

import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelMaker;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.shared.Lock;

public class JenaServiceTest {

    private Mockery context;

    @BeforeMethod
    public void setUp() {
	context = new Mockery();
    }

    @Test
    public void testSubstractModels() {
	
	final String subtractedFromModelName = "subtractedFromModel";
	final String subtractedByModelName = "subtractedByModel";
	final String resultModelName = "resultModel";

	final Model differenceModel = context.mock(Model.class, "differenceModel");
	context.checking(new Expectations() {
	    {
	    }
	});

	final Model subsetModel = context.mock(Model.class, "subsetModel");
	context.checking(new Expectations() {
	    {
	    }
	});
	
	final Model sourceModel = context.mock(Model.class, "sourceModel");
	context.checking(new Expectations() {
	    {
		exactly(1).of(sourceModel).difference(subsetModel); will(returnValue(differenceModel));
	    }
	});
	
	final Model destinationModel = context.mock(Model.class, "destinationModel");
	context.checking(new Expectations() {
	    {
		exactly(1).of(destinationModel).add(differenceModel);
	    }
	});	
	
	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		exactly(1).of(modelBuilder).createOntologyModelFromName(subtractedFromModelName); will(returnValue(sourceModel));
		exactly(1).of(modelBuilder).createOntologyModelFromName(subtractedByModelName); will(returnValue(subsetModel));
		exactly(1).of(modelBuilder).createOntologyModelFromName(resultModelName); will(returnValue(destinationModel));
	    }
	});
	
	JenaService jenaService = new JenaServiceImpl(null, null, modelBuilder, null);
	jenaService.subtractModels(subtractedFromModelName, subtractedByModelName, resultModelName);
    }

    @Test
    public void testCreateModel() {
	
	final String modelName = "modelName";
	
	final ModelMaker modelMaker = context.mock(ModelMaker.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelMaker).createModel(modelName);
	    }
	});

	JenaService jenaService = new JenaServiceImpl(modelMaker, null, null, null);
	jenaService.createModel("modelName");
	context.assertIsSatisfied();
    }

    @Test
    public void testDeleteModel() {
	
	final String modelName = "modelName";
	
	final ModelMaker modelMaker = context.mock(ModelMaker.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelMaker).removeModel(modelName);
	    }
	});
	
	JenaService jenaService = new JenaServiceImpl(modelMaker, null, null, null);
	jenaService.deleteModel("modelName");
	context.assertIsSatisfied();
    }

    @Test
    public void testClearModel() {
	
	final String modelName = "modelName";
	
	final ModelMaker modelMaker = context.mock(ModelMaker.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelMaker).removeModel(modelName);
		oneOf(modelMaker).createModel(modelName);
	    }
	});

	JenaService jenaService = new JenaServiceImpl(modelMaker, null, null, null);
	jenaService.clearModel("modelName");
	context.assertIsSatisfied();
    }

    @Test
    public void testRemoveModel() {
	
	final String modelName = "modelName";
	
	final ModelMaker modelMaker = context.mock(ModelMaker.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelMaker).removeModel(modelName);
	    }
	});	

	JenaService jenaService = new JenaServiceImpl(modelMaker, null, null, null);
	jenaService.removeModel("modelName");
	context.assertIsSatisfied();
    }

  /*  @Test
    public void testRenameBlankNode() {
	
	final String namespaceEtcStr = "namespaceEtcStr";
	final String destinationModelName = "destinationModelName";
	final String[] sourceModelNames = {"sourceModel0"};
	
	final Model subModel = context.mock(Model.class, "subModel");
	context.checking(new Expectations() {
	    {
	    }
	});	

	final OntModel sourceOntologyModel = context.mock(OntModel.class, "sourceModel");
	context.checking(new Expectations() {
	    {
		exactly(1).of(sourceOntologyModel).addSubModel(subModel);
	    }
	});
	
	final Model renamedModel = context.mock(Model.class, "renamedModel");
	context.checking(new Expectations() {
	    {
	    }
	});	
		
	final Model destinationModel = context.mock(Model.class, "destinationModel");
	context.checking(new Expectations() {
	    {
		exactly(1).of(destinationModel).enterCriticalSection(Lock.WRITE);
		exactly(1).of(destinationModel).add(renamedModel);
		exactly(1).of(destinationModel).leaveCriticalSection();
	    }
	});	
	
	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		exactly(1).of(modelBuilder).createOntologyModelFromSpec(OntModelSpec.OWL_DL_MEM); will(returnValue(sourceOntologyModel));
		exactly(1).of(modelBuilder).createOntologyModelFromName(destinationModelName); will(returnValue(destinationModel));
		exactly(1).of(modelBuilder).createOntologyModelFromName(sourceModelNames[0]); will(returnValue(subModel));
	    }
	});
	
	final JenaHelper jenaHelper = context.mock(JenaHelper.class);
	context.checking(new Expectations() {
	    {
		exactly(1).of(jenaHelper).renameBlankNodes(sourceOntologyModel, namespaceEtcStr); will(returnValue(renamedModel));
	    }
	});

	JenaService jenaService = new JenaServiceImpl(null, jenaHelper, modelBuilder, null)
	{
	    protected boolean isDebugEnabled() {
		return false;
	    }
	};
	jenaService.renameBlankNode(namespaceEtcStr, sourceModelNames, destinationModelName);
	context.assertIsSatisfied();
    }*/

    @Test
    public void testGetModelAsOutputStream() {

	final String modelName = "dummyModelName";
	final String format = "format";

	final Model model = context.mock(Model.class);
	context.checking(new Expectations() {
	    {
		oneOf(model).enterCriticalSection(Lock.READ);
		oneOf(model).leaveCriticalSection();
		oneOf(model).write(with(any(PrintWriter.class)), with(format));
	    }
	});
	
	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelBuilder).createOntologyModelFromName(modelName); will(returnValue(model));
	    }
	});
	
	final JenaHelper jenaHelper = context.mock(JenaHelper.class);
	context.checking(new Expectations() {
	    {
		oneOf(jenaHelper).validateRDFFormat(format); will(returnValue(true));
	    }
	});

	JenaService jenaService = new JenaServiceImpl(null, jenaHelper, modelBuilder, null);
	jenaService.getModelAsOutputStream(modelName, format);

	context.assertIsSatisfied();
    }

    @Test
    public void testPopulateModelwithSPARQL() {

	final String sparqlQuery = "sparqlQuery";
	final String destinationModelName = "dummyModelName";
	final String[] sourceModelNames = {"sourceModelName0"};

	final Model destinationModel = context.mock(Model.class, "destinationModel");
	context.checking(new Expectations() {
	    {
	    }
	});

	final Model subModel = context.mock(Model.class, "subModel");
	context.checking(new Expectations() {
	    {
	    }
	});

	final OntModel sourceOntologyModel = context.mock(OntModel.class);
	context.checking(new Expectations() {
	    {
		oneOf(sourceOntologyModel).addSubModel(subModel); ;
	    }
	});

	final SparqlQueryEngine sparqlQueryEngine = context.mock(SparqlQueryEngine.class);
	context.checking(new Expectations() {
	    {
		oneOf(sparqlQueryEngine).populate(sparqlQuery, sourceOntologyModel, destinationModel); ;
	    }
	});
	
	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelBuilder).createOntologyModelFromSpec(OntModelSpec.OWL_DL_MEM); will(returnValue(sourceOntologyModel));
		oneOf(modelBuilder).createOntologyModelFromName(destinationModelName); will(returnValue(destinationModel));
		oneOf(modelBuilder).createOntologyModelFromName(sourceModelNames[0]); will(returnValue(subModel));
	    }
	});

	JenaService jenaService = new JenaServiceImpl(null, null, modelBuilder, sparqlQueryEngine)
	{
	    protected boolean isDebugEnabled() {
		return false;
	    }
	};
	jenaService.populateModelwithSPARQL(sparqlQuery, sourceModelNames, destinationModelName, false);

	context.assertIsSatisfied();
    }

    @Test
    public void testAddDefaultSourceModels() {

	final Model jenaModel = context.mock(Model.class, "jenaModel");
	context.checking(new Expectations() {
	    {
	    }
	});

	final Model baseModel = context.mock(Model.class, "baseModel");
	context.checking(new Expectations() {
	    {
	    }
	});

	final Model virtoKb2Model = context.mock(Model.class, "virtoKb2Model");
	context.checking(new Expectations() {
	    {
	    }
	});

	final OntModel ontologyModel = context.mock(OntModel.class);
	context.checking(new Expectations() {
	    {
		exactly(1).of(ontologyModel).addSubModel(jenaModel);
		exactly(1).of(ontologyModel).addSubModel(baseModel);
		exactly(1).of(ontologyModel).addSubModel(virtoKb2Model);
	    }
	});

	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelBuilder).createOntologyModelFromName("vitro:jenaOntModel"); will(returnValue(jenaModel));
		oneOf(modelBuilder).createOntologyModelFromName("vitro:baseOntModel"); will(returnValue(baseModel));
		oneOf(modelBuilder).createOntologyModelFromName("http://vitro.mannlib.cornell.edu/default/vitro-kb-2"); will(returnValue(virtoKb2Model));
	    }
	});

	JenaServiceImpl jenaService = new JenaServiceImpl(null, null, modelBuilder, null)
	{
	    protected boolean isDebugEnabled() {
		return false;
	    }
	};
	jenaService.addDefaultSourceModels(ontologyModel);

	context.assertIsSatisfied();
    }

    @Test
    public void testAddRDF() {

	final String modelName = "modelName";
	final String subject = "subject";
	final String predicate = "predicate";
	final String object = "object";

	final Resource resource = context.mock(Resource.class);
	context.checking(new Expectations() {
	    {
	    }
	});

	final Property property = context.mock(Property.class);
	context.checking(new Expectations() {
	    {
	    }
	});

	final Literal literal = context.mock(Literal.class);
	context.checking(new Expectations() {
	    {
	    }
	});

	final Statement statement = context.mock(Statement.class);
	context.checking(new Expectations() {
	    {
	    }
	});

	final OntModel ontologyModel = context.mock(OntModel.class);
	context.checking(new Expectations() {
	    {
		exactly(1).of(ontologyModel).createResource(subject); will(returnValue(resource));
		exactly(1).of(ontologyModel).createProperty(predicate); will(returnValue(property));
		exactly(1).of(ontologyModel).createLiteral(object); will(returnValue(literal));
		exactly(1).of(ontologyModel).createStatement(resource, property, literal); will(returnValue(statement));
		exactly(1).of(ontologyModel).add(statement);
	    }
	});

	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelBuilder).createOntologyModelFromName(modelName); will(returnValue(ontologyModel));
	    }
	});

	JenaServiceImpl jenaService = new JenaServiceImpl(null, null, modelBuilder, null);
	jenaService.addRDF(modelName, subject, predicate, object);

	context.assertIsSatisfied();
    }

    @Test
    public void testGetRDF() {

    }

    @Test
    public void testDeleteRDF() {

	final String modelName = "modelName";
	final String subject = "subject";
	final String predicate = "predicate";
	final String object = "object";

	final OntModel ontologyModel = context.mock(OntModel.class);
	context.checking(new Expectations() {
	    {
		oneOf(ontologyModel).listStatements(); will(returnValue(null));
	    }
	});

	final ModelBuilder modelBuilder = context.mock(ModelBuilder.class);
	context.checking(new Expectations() {
	    {
		oneOf(modelBuilder).createOntologyModelFromName(modelName); will(returnValue(ontologyModel));
	    }
	});

	JenaServiceImpl jenaService = new JenaServiceImpl(null, null, modelBuilder, null);
	jenaService.deleteRDF(modelName, subject, predicate, object);

	context.assertIsSatisfied();
    }

}
